package com.hevs.samplewebapp.server.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.jdo.FetchGroup;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.google.appengine.api.datastore.Key;
import com.hevs.samplewebapp.server.entities.User;

/**
 * Implementation of the DAO interface for the Users
 * 
 * @author Lionel Rey
 * @date 02.04.12
 */
public class UserDAOImpl implements UserDAO{

	@SuppressWarnings("unchecked")
	@Override
	/**
	 * Methode to get all the users
	 * @return
	 * a list of user
	 */
	public List<User> getAll() {
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		

		Query query = pm.newQuery(User.class);
		try{
			List<User> results = (List<User>) query.execute();
			return (List<User>) pm.detachCopyAll(results);
		}
		finally{
			pm.close();
		}
	}

	@Override
	/**
	 * Method to retrieve a user by its Key
	 * @param key
	 * key of the user
	 * @return
	 * a user
	 */
	public User getUser(Key key) {
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		

		try {
			User u = pm.getObjectById(User.class, key);
			return pm.detachCopy(u);
		}
		finally{
			pm.close();
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	/**
	 * Method to retrieve a user by its Login
	 * @param login
	 * login of the user
	 * @return
	 * a user
	 */
	public User getUserByLogin(String login) {

		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		Query query = pm.newQuery(User.class);
	    query.setFilter("login == loginParam");
	    query.declareParameters("String loginParam");
	    try {
	    	List<User> results = (List<User>) query.execute(login);
			User result = results.get(0);
			return pm.detachCopy(result);
		}
	    finally{
			pm.close();
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	/**
	 * Method to retrieve a user by Email
	 * @param mail
	 * email of the user
	 * @return
	 * a user
	 */
	public User getUserByMail(String mail) {

		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		Query query = pm.newQuery(User.class);
		query.setFilter("email == emailParam");
		query.declareParameters("String emailParam");
		try{
			List<User> results = (List<User>) query.execute(mail);
			User result = results.get(0);
			return pm.detachCopy(result);
		}
		finally{
			pm.close();
		}
	}

	@Override
	/**
	 * Method to update a user's informations
	 * @param user
	 * the user to update
	 */
	public void update(User user) {
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		try{
			
			if(user.getKey()!= null){
				String login = user.getLogin();
				String firstName = user.getFirstName();
				String lastName = user.getLastName();
				String email = user.getEmail();
				int credentialLevel = user.getCredentialLevel();
				String password = user.getPassword();
				
				user = pm.getObjectById(User.class, user.getKey());
				user.setLogin(login);
				user.setFirstName(firstName);
				user.setLastName(lastName);
				user.setEmail(email);
				user.setCredentialLevel(credentialLevel);
				user.setPassword(password);
				
				pm.makePersistent(user);
			}
			else{
				pm.makePersistent(user);
			}
		}
		finally {
			pm.close();
		}
	}

	@Override
	/**
	 * Method to delete a user
	 * @param user
	 * the user to delete 
	 */
	public void remove(User user) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			User u = pm.getObjectById(User.class, user.getKey());
			pm.deletePersistent(u);
		}
		finally{
			pm.close();
		}
	}

	@Override
	/**
	 * Method to retrieve the List of user granted by the user
	 * @param local
	 * the user who granted the other
	 * @return
	 * a list of users
	 */
	public List<User> getGrantedUsers(User local) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.getFetchPlan().setGroup(FetchGroup.ALL);

		List<User> grantedUsers = new ArrayList<User>();
		try{
			User u = pm.getObjectById(User.class, local.getKey());
			Set<Key> grantedUserKeys = u.getGrantedUsers();
			
			for(Key grantedUserKey : grantedUserKeys){
				User grantedUser = new User();
					User grantedUserFromKeyList =pm.getObjectById(User.class, grantedUserKey);
					grantedUser.setFirstName(grantedUserFromKeyList.getFirstName());
					grantedUser.setLastName(grantedUserFromKeyList.getLastName());
					grantedUser.setEmail(grantedUserFromKeyList.getEmail());
					grantedUsers.add(grantedUser);
			}
				return (List<User>) grantedUsers;
		}
		finally{
			pm.close();
		}
		
	}

	@Override
	/**
	 * Method to grant a user to see medical data
	 * @param local
	 * the owner of the medical data
	 * @param remote
	 * the granted user
	 */
	public void grantAccess(User local, User remote) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try{
			User u1 = pm.getObjectById(User.class, local.getKey());
			u1.getGrantedUsers().add(remote.getKey());
			User u2 = pm.getObjectById(User.class, remote.getKey());
			u2.getGrantedUsers().add(local.getKey());
			pm.makePersistent(u1);
			pm.makePersistent(u2);
			
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally{
			pm.close();
		}
	}

	@Override
	/**
	 * Method to revoke a user to see medical data
	 * @param local
	 * the owner of the medical data
	 * @param remote
	 * the revoked user
	 */
	public void revokeAccess(User local, User remote) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try{
			
			User u1 = pm.getObjectById(User.class, local.getKey());
			u1.getGrantedUsers().remove(remote.getKey());
			User u2 = pm.getObjectById(User.class, remote.getKey());
			u2.getGrantedUsers().remove(local.getKey());
			
			pm.makePersistent(u1);
			pm.makePersistent(u2);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally{
			pm.close();
		}
		
	}
}